#!/usr/bin/env python3
# filename:

from flask import Flask, redirect, url_for
from flask_principal import identity_loaded, UserNeed, RoleNeed
from flask_login import current_user


from hzsaiblog.models import db, Tag, Role, User, Post
from hzsaiblog.config import devConfig
from hzsaiblog.controllers import blog, main, admin
from hzsaiblog.extensions import (
        bcrypt,
        login_manager,
        principals,
        flask_admin)


# factory model
def create_app(object_name):

    app = Flask(__name__)

    # init config from object `devConfig`
    app.config.from_object(devConfig)

    # database init the app
    # will load the SQLALCHEMY_DATABASE_URI from config.py to the db object
    db.init_app(app)

    # init the Flask-Bcrypt via app
    bcrypt.init_app(app)

    # init the flask_login
    login_manager.init_app(app)

    #
    principals.init_app(app)

    # init flask_admin
    flask_admin.init_app(app)

    # register view function into flask-admin
    flask_admin.add_view(admin.CustomView(name='Custom'))
    models = [Role, Tag, User, Post]

    # appear in the same col `Models`
    for model in models:
        flask_admin.add_view(admin.CustomModelView(
            model,
            db.session,
            category='Models'))

    @identity_loaded.connect_via(app)
    def on_identity_loaded(sender, identity):
        """

        Change the role via add the Need object into Role
            Need the access the app object.
        """

        # Set the identity user object
        identity.user = current_user

        # Add the UserNeed to the identity user object
        if hasattr(current_user, 'id'):
            identity.provides.add(UserNeed(current_user.id))

        # Add each role toe the identity user object
        if hasattr(current_user, 'roles'):
            for role in current_user.roles:
                identity.provides.add(RoleNeed(role.name))

    @app.route('/')
    def index():
        # redirect the request from '/' to '/blog/'
        return redirect(url_for('blog.home'))

    # register the Blueprint into app
    app.register_blueprint(blog.blog_blueprint)
    app.register_blueprint(main.main_blueprint)

    return app
